﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using Diploma.Models.IRepositories;
using Diploma.Models.Utils.PasswordsUtils;
using DiplomaWeb.Utils.PasswordsUtils;

namespace Diploma.Models.Repositories
{
    internal class UsersRepository : IUsersRepository
    {
        private readonly DiplomaEntities dataContext;

        public UsersRepository(DiplomaEntities dataContext)
        {
            this.dataContext = dataContext;
        }

        public User GetUserByEmail(string email, bool includeDeleted)
        {
            IQueryable<User> users =
                dataContext.Users.Where(u => u.Email.Trim().ToLower().Equals(email.Trim().ToLower()));
            if (!includeDeleted)
                return users.FirstOrDefault(u => u.DeletionDate == null);
            return users.FirstOrDefault();
        }

        public User GetUserById(Guid userId)
        {
            return dataContext.Users.FirstOrDefault(u => u.UserId == userId && u.DeletionDate == null);
        }

        public bool ValidateUser(string userEmail, string password)
        {
            password = GetMD5Hash(password);
            User user = GetUserByEmail(userEmail, false);
            if (user == null)
                return false;
            IPasswordsUtil passwordUtil = new SimplePasswordUtil();
            
            return passwordUtil.ValidatePassword(password, user.Password);
        }

        public User GeneratePassword(Guid id)
        {
            User user = GetUserById(id);
            if (user == null)
                throw new NullReferenceException(String.Format("Can't find user with {0} guid", id));

            user.Password = GetMD5Hash(PasswordGenerator.Encrypt(PasswordGenerator.GeneratePassword()));
            dataContext.SaveChanges();

            return user;
        }

        public string GenerateHash(string userEmail)
        {
            if(String.IsNullOrWhiteSpace(userEmail))
                throw new ArgumentNullException("userEmail");

            var hash = PasswordGenerator.Encrypt(PasswordGenerator.GeneratePassword());
            var user = GetUserByEmail(userEmail, false);
            user.HashCode = hash;
            dataContext.SaveChanges();

            return hash;
        }

        public bool ValidateUserHash(string userEmail, string hash)
        {
            User user = GetUserByEmail(userEmail, false);
            if (user == null)
                return false;
            IPasswordsUtil passwordUtil = new SimplePasswordUtil();

            return passwordUtil.ValidatePassword(hash, user.HashCode);
        }

        public void UpdatePassword(Guid guid, string password)
        {
            var user = dataContext.Users.FirstOrDefault(r => r.UserId == guid);
            if(user != null)
            {
                user.Password = GetMD5Hash(password);
                dataContext.SaveChanges();
            }
        }

        public IEnumerable<User> GetUsers()
        {
            return dataContext.Users.ToList();
        }

        private string GetMD5Hash(string input)
        {
            MD5CryptoServiceProvider x = new MD5CryptoServiceProvider();
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
            bs = x.ComputeHash(bs);
            var s = new System.Text.StringBuilder();
            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string password = s.ToString();
            return password;
        }
    }
}